<!--
 * @Author: zhayang
 * @LastEditors: DeluxePig 250293786@qq.com
 * @Date: 2024-06-19 22:51:53
 * @LastEditTime: 2024-07-24 00:37:57
 * @Description: 侧边tab
-->
<template>
  <div class="sider-tabs fit overflow-hidden flex">
    <div class="sider-tabs-wrap full-h w-120 m-r-40">
      <div v-for="(item, index) in options" :key="index"
        class="sider-tab full-w flex items-center h-40 m-b-10 last:m-0 text-#1C1D23 text-14 transition p-x-8 p-y-12 cursor-pointer"
        :class="{
          'bg-#E6FEFBFF rd-4': active === index
        }" @click="changeActive(index)">
        <img class="w16 h-16 m-r-8" :src="item.img" />
        {{ item.label }}
      </div>
    </div>
    <!-- 右侧 -->

    <div v-show="active === 0" class="full-h column w-228 m-r-20">
      <SegmentTabs v-model="bgActive" :data="options[0].menu" class="col-auto m-b-20" />
      <div class="pick-area h-col">
        <!-- 颜色 -->
        <div v-show="bgActive === 0" class="fit overflow-auto">
          <div class="full-w grid grid-cols-2 gap-12">
            <div v-for="item in colorList" :key="item.id" class="full-w h-72 cursor-pointer rd-4"
              :style="{ backgroundColor: item.payload }" :class="{
                picked: bgPick.origin === item.payload
              }" @click="pickBg(item.payload, 'color')"></div>
          </div>
        </div>
        <!-- 公共 -->
        <div v-show="bgActive === 1" class="fit overflow-y-auto">
          <div class="full-w grid grid-cols-2 gap-12 overflow-hidden">
            <div v-for="item in imgList" :key="item.payload" class="full-w cursor-pointer rd-4 pic-item" :class="{
              picked: bgPick.origin === item.payload
            }" @click="pickBg(item.payload, 'url')">
              <img :src="item.payload" class="full-w pic-item" />
            </div>
          </div>
        </div>
        <!-- 上传 -->
        <div v-show="bgActive === 2" class="fit overflow-y-auto">
          <div class="full-w grid grid-cols-2 gap-12 overflow-hidden">
            <UpImgList class="pic-item" :url="uploadUrl" up-text="上传图片" sub-up-text="(9:16)" @getImg="setImg" />
            <div v-for="(item, uindex) in uploadList" :key="item.value" class="full-w pic-item cursor-pointer relative"
              :class="{
                picked: bgPick.origin === item.payload
              }" @click="pickBg(item.payload, 'url')">
              <div class="absolute right--24 top--24 w-48 h-48 bg-#ffffff66 rd-9999 center cursor-pointer"
                @click.stop="deletePic(item, uindex)">
                <span class="iconfont icon-x absolute bottom-6 left-6 text-#ffffffcc text-9"></span>
              </div>
              <img :src="item.payload" class="fit rd-4" />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div v-show="active === 1" class="full-h column w-228 m-r-20">
      <SegmentTabs v-model="actorActive" :data="options[1].menu" class="col-auto m-b-20" />

      <div class="pick-area h-col">
        <div v-show="actorActive === 0" class="fit overflow-auto full-w grid grid-cols-2 gap-12">
          <div v-for="item in actorCommonList" :key="item.uid" class="full-w cursor-pointer column"
            @click="pickActor(item)">
            <div class="full-w h-col rd-4 pic-item relative center border border-#e0e2e7" :class="{
              picked: actorPick.uid === item.uid
            }">
              <img :src="item.actor_thumbnail" class="actor-img" />
              <div class="absolute bottom-0 right-0 w-20 h-20 text-#1C1F2399 center"
                @click.stop="openVideo(item.actor_demo_url)">
                <i class="iconfont icon-bofang"></i>
              </div>
            </div>

            <div class="img-info c-#1c1f23 text-12 line-height-14 m-t-4 h-col-auto ellipsis" :title="item.actor_name">
              {{ item.actor_name }}
            </div>
          </div>
        </div>
        <div v-show="actorActive === 1" class="fit overflow-auto full-w grid grid-cols-2 gap-12">
          <div v-for="item in actorCustomList" :key="item.uid" class="full-w cursor-pointer column"
            @click="pickActor(item)">
            <div class="full-w h-col rd-4 pic-item relative transition" :class="{
              picked: actorPick.uid === item.uid
            }">
              <img :src="item.actor_thumbnail" class="full-w pic-item" />
              <div class="absolute bottom-0 right-0 w-20 h-20 text-#1C1F2399 center"
                @click.stop="openVideo(item.actor_demo_url)">
                <i class="iconfont icon-bofang"></i>
              </div>
            </div>

            <div class="img-info c-#1c1f23 text-12 line-height-14 m-t-4 h-col-auto ellipsis" :title="item.actor_name">
              {{ item.actor_name }}
            </div>
          </div>
        </div>
      </div>
    </div>
    <div v-show="active === 2" class="full-h column w-228 m-r-20">
      <SegmentTabs v-model="voiceActive" :data="options[2].menu" class="m-b-20 col-auto" />
      <div class="pick-area h-col">
        <div v-show="voiceActive === 0" class="fit overflow-auto column gap-12">
          <div v-for="item in voiceCommonList" :key="item.uid"
            class="full-w rd-4 relative min-h-72 bg-#F4F5F9 p-x-20 p-y-14 flex items-center" :class="{
              picked: voicePick.uid === item.uid
            }" @click="pickVoice(item)">
            <div class="voice-header w-44 h-44 m-r-8 col-auto">
              <img class="fit" :src="require('@/assets/images/user-logo.png')" />
            </div>
            <div class="voice-content col m-r-8 column cursor-pointer">
              <div class="full-w text-14 line-height-16 c-#1c1f23 ellipsis">
                {{ item.voice_name }}
              </div>
              <span class="text-10 c-#9E9E9E m-t-4 full-w">
                {{ item.voice_description }}
              </span>
            </div>
            <div class="voice-icon w-24 h-24 text-#1C1F2399 center col-auto text-24" @click="openVoice(item.voice_url)">
              <i class="iconfont icon-bofang"></i>
            </div>
          </div>
        </div>
        <div v-show="voiceActive === 1" class="fit overflow-auto column gap-12">
          <div v-for="item in voiceCustomList" :key="item.uid"
            class="full-w rd-4 relative min-h-72 bg-#F4F5F9 p-x-20 p-y-14 flex items-center" :class="{
              picked: voicePick.uid === item.uid
            }" @click="pickVoice(item)">
            <div class="voice-header w-44 h-44 m-r-8 col-auto">
              <img class="fit" :src="require('@/assets/images/user-logo.png')" />
            </div>
            <div class="voice-content col m-r-8 column cursor-pointer">
              <div class="full-w text-14 line-height-16 c-#1c1f23 ellipsis">
                {{ item.voice_name }}
              </div>
              <span class="text-10 c-#9E9E9E m-t-4 full-w">
                {{ item.voice_description }}
              </span>
            </div>
            <div class="voice-icon w-24 h-24 text-#1C1F2399 center col-auto text-24" @click="openVoice(item.voice_url)">
              <i class="iconfont icon-bofang"></i>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="full-h center col overflow-hidden bg-#f2f2f2 dragg-box">
      <div ref="canvasRef" class="w-360 h-640 rd-4 relative" :style="style">
        <img v-if="bgPick.type === 'url'" :src="bgPick.value" class="fit absolute left-0 top-0" />
        <Draggable :key="key" class="fit" :data="dragData" @updata="updataDragData" />
      </div>
      <div class="mb mb-left"> </div>
      <div class="mb  mb-right"> </div>
    </div>

    <el-dialog title="预览视频" :visible.sync="videoVisible" destroy-on-close>
      <video :src="videoUrl" controls class="full-w pic-item2"></video>
    </el-dialog>
    <el-dialog title="预览音色" :visible.sync="voiceVisible" destroy-on-close>
      <video :src="voiceUrl" controls class="full-w pic-item2"></video>
    </el-dialog>
  </div>
</template>

<script>
import SegmentTabs from '@/components/bmp/segment-tabs.vue'
import UpImgList from '@/components/upload/up-image-list-limit.vue'
import {
  getAddConfig,
  getCommonActor,
  getCommonVoice,
  generateModel,
  getCustomActor,
  getCustomVoice,
  savegenVideoApi,
  deletVideoApi
} from '@/api/model'
import Draggable from '@/components/bmp/draggable2.vue'
import { Loading } from 'element-ui'
import html2Canvas from 'html2canvas'
import axios from 'axios'
import { getToken } from '@/utils/auth'
import { getStsApi } from '@/api/upload'
export default {
  components: {
    SegmentTabs,
    UpImgList,
    Draggable
  },
  props: {
    modelUniqueid: {
      type: String,
      default: ''
    },
    cacheData: {
      type: Object,
      default: () => { }
    }
  },
  data() {
    return {
      active: 0,
      options: [
        {
          label: '背景',
          value: 0,
          img: require('@/assets/images/model/bg.png'),
          menu: [
            {
              label: '颜色',
              value: 0
            },
            {
              label: '公共',
              value: 1
            },
            {
              label: '上传',
              value: 2
            }
          ]
        },
        {
          label: '人物',
          value: 1,
          img: require('@/assets/images/model/person.png'),
          menu: [
            {
              label: '通用人物',
              value: 0
            },
            {
              label: '定制人物',
              value: 1
            }
          ]
        },
        {
          label: '音色',
          value: 2,
          img: require('@/assets/images/model/sound.png'),
          menu: [
            {
              label: '公共',
              value: 0
            },
            {
              label: '定制',
              value: 1
            }
          ]
        }
      ],
      bgActive: 0,
      colorList: [],
      imgList: [],
      bgPick: {
        type: '',
        value: '',
        origin: ''
      },
      actorActive: 0,
      actorCommonList: [],
      actorCustomList: [],
      actorPick: {},
      videoVisible: false,
      videoUrl: '',

      voiceActive: 0,
      voiceCommonList: [],
      voiceCustomList: [],
      voicePick: {},
      voiceUrl: '',
      voiceVisible: false,

      personActive: 0,
      uploadList: [],
      uploadUrl: '',

      dragData: {
        x: 0,
        y: 0,
        w: 360,
        h: 640,
        src: ''
      },
      key: 1,
      stsData: {}
    }
  },
  computed: {
    actorList() {
      return [...this.actorCommonList, ...this.actorCustomList]
    },
    voiceList() {
      return [...this.voiceCommonList, ...this.voiceCustomList]
    },
    style() {
      return {
        background:
          this.bgPick.type === 'color' ? this.bgPick.value : 'transparent'
      }
    }
  },
  watch: {
    cacheData: {
      handler(nv) {
        if (Object.keys(nv).length) {
          this.setOption()
        }
      },
      immediate: true,
      deep: true
    }
  },
  created() {
    this.getConfig()
    this.setData()
  },
  methods: {
    setActorAgain() {
      // 防止异步影响
      if (this.actorList.length) {
        const picked =
          this.actorList.find(
            (i) =>
              i.uid ===
              this.cacheData?.generate_config?.video_generate_actor_uid
          ) || {}
        if (this.cacheData?.generate_config) {
          this.pickActor(picked, this.cacheData?.generate_config)
        }
      }
    },
    setVoiceAgain() {
      // 防止异步影响
      if (this.voiceList.length) {
        this.voicePick =
          this.voiceList.find(
            (i) =>
              i.uid ===
              this.cacheData?.generate_config?.video_generate_voice_uid
          ) || {}
      }
    },
    setOption() {
      const twoData = this.cacheData.generate_config
      this.bgPick.type = twoData.video_generate_layout_background_type
      this.bgPick.value = twoData.video_generate_layout_background_background
      this.bgPick.origin = twoData.video_generate_layout_background_background
      this.bgActive = this.bgPick.type === 'color' ? 0 : 1
      // 这里有异步可能性
      this.setActorAgain()
      this.setVoiceAgain()
    },
    changeActive(index) {
      this.active = index
    },
    getCommon() {
      return new Promise((resolve, reject) => {
        getCommonActor()
          .then((res) => {
            if (res.code === 0 && res?.data) {
              this.actorCommonList = res.data.map((i) => {
                return {
                  ...i,
                  actor_rectangle_png:
                    process.env.VUE_APP_ALI_WEB + i.actor_rectangle_png,
                  actor_thumbnail:
                    process.env.VUE_APP_ALI_WEB + i.actor_thumbnail,
                  actor_demo_url: process.env.VUE_APP_ALI_WEB + i.actor_demo_url
                }
              })
              resolve()
            }
          })
          .catch(() => {
            this.$message.error('获取错误，请重试4')
            reject()
          })
      })
    },
    getCustom() {
      return new Promise((resolve, reject) => {
        getCustomActor()
          .then((res) => {
            if (res.code === 0 && res?.data) {
              this.actorCustomList = res.data.map((i) => {
                return {
                  ...i,
                  actor_rectangle_png:
                    process.env.VUE_APP_ALI_WEB + i.actor_rectangle_png,
                  actor_thumbnail:
                    process.env.VUE_APP_ALI_WEB + i.actor_thumbnail,
                  actor_demo_url: process.env.VUE_APP_ALI_WEB + i.actor_demo_url
                }
              })
              resolve()
            }
          })
          .catch(() => {
            this.$message.error('获取错误，请重试')
            reject()
          })
      })
    },
    getVoiceCommon() {
      return new Promise((resolve, reject) => {
        getCommonVoice()
          .then((res) => {
            if (res.code === 0 && res?.data) {
              this.voiceCommonList = res.data.map((i) => {
                return {
                  ...i,
                  voice_url: process.env.VUE_APP_ALI_WEB + i.voice_url
                }
              })
              resolve()
            }
          })
          .catch(() => {
            this.$message.error('获取错误，请重试')
            reject()
          })
      })
    },
    getVoiceCustom() {
      return new Promise((resolve, reject) => {
        getCustomVoice()
          .then((res) => {
            if (res.code === 0 && res?.data) {
              this.voiceCustomList = res.data.map((i) => {
                return {
                  ...i,
                  voice_url: process.env.VUE_APP_ALI_WEB + i.voice_url
                }
              })
              resolve()
            }
          })
          .catch(() => {
            this.$message.error('获取错误，请重试')
            reject()
          })
      })
    },
    getConfig() {
      const loadingInstance = Loading.service()
      getAddConfig()
        .then((res) => {
          if (res.code === 0) {
            this.colorList = res.data.filter((i) => i.group === 'bg-color')
            this.imgList = res.data.filter((i) => i.group === 'bg-img')
          }
        })
        .catch(() => {
          this.$message.error('获取错误，请重试')
        })
      getAddConfig({ common_switch: 0 })
        .then((res) => {
          if (res.code === 0) {
            this.uploadList = res.data.filter((i) => i.group === 'bg-img')
          }
        })
        .catch(() => {
          this.$message.error('获取错误，请重试')
        })

      // 人物
      Promise.allSettled([this.getCommon(), this.getCustom()]).then(() => {
        this.setActorAgain()
      })
      // 声音
      Promise.allSettled([this.getVoiceCommon(), this.getVoiceCustom()]).then(
        () => {
          this.setVoiceAgain()
        }
      )
      this.$nextTick(() => {
        loadingInstance.close()
      })
    },
    pickBg(value, type) {
      this.bgPick = {
        value,
        type,
        origin: value
      }
    },
    pickActor(value, params) {
      this.key += 1
      this.actorPick = value
      const isVertical =
        +this.actorPick.actor_width < +this.actorPick.actor_height
      let obj = {}
      if (params) {
        let x = +params?.video_generate_layout_avatar_x / 3 + +params?.video_generate_layout_avatar_width / 3 ?? 0
        let y =
          +params?.video_generate_layout_avatar_y / 3 +
          +params?.video_generate_layout_avatar_height / 3 ?? 0
        obj = {
          x: Number(x),
          y: Number(y),
          w: +params?.video_generate_layout_avatar_width / 3 ?? 360,
          h:
            +params?.video_generate_layout_avatar_height / 3 ??
            (isVertical ? 640 : 202.5),
          src: value.actor_rectangle_png
        }
      } else {
        obj = {
          x: 360,
          y: isVertical ? 640 : 421.25,
          w: 360,
          h: isVertical ? 640 : 202.5,
          src: value.actor_rectangle_png
        }
      }
      this.$nextTick(() => {
        this.dragData = obj
      })
    },
    pickVoice(value) {
      this.voicePick = value
    },
    openVideo(url) {
      this.videoUrl = url
      this.videoVisible = true
    },
    openVoice(url) {
      this.voiceUrl = url
      this.voiceVisible = true
    },
    setImg(url, name) {
      this.uploadList.push({
        payload: url,
        title: name
      })
      const data = {
        title: name,
        group: 'bg-img',
        payload: url,
        size: '1080*1920',
        ratio: '9:16'
      }
      savegenVideoApi(data)
        .then((res) => {
          this.uploadList[this.uploadList.length - 1].id = res.data.id
          // this.$message.error('获取错误，请重试')
        })
        .catch(() => {
          this.$message.error('获取错误，请重试')
        })
    },
    deletePic(item, index) {
      this.uploadList.splice(index, 1)
      if (item.id && item.id !== null) {
        deletVideoApi({ id: item.id })
          .then(() => {
            // this.$message.error('获取错误，请重试')
          })
          .catch(() => {
            this.$message.error('获取错误，请重试')
          })
      }
    },
    updataDragData(x, y, w, h) {
      this.$set(this.dragData, 'x', x)
      this.$set(this.dragData, 'y', y)
      w && this.$set(this.dragData, 'w', w)
      h && this.$set(this.dragData, 'h', h)
    },
    backgroundExchange() {
      return new Promise((resolve, reject) => {
        try {
          if (this.bgPick.type === 'color') {
            resolve()
          } else {
            const imageUrl = this.bgPick.value
            const image = new Image()
            image.crossOrigin = 'anonymous'
            // 设置图片的src属性为你想要转换的图片URL
            image.src = imageUrl
            // 当图片加载完成后执行回调函数
            image.onload = () => {
              // 创建一个canvas元素
              const canvas = document.createElement('canvas')
              const ctx = canvas.getContext('2d')
              // 将图片绘制到canvas上
              canvas.width = image.width
              canvas.height = image.height
              ctx.drawImage(image, 0, 0)

              const base64data = canvas.toDataURL('image/png')
              this.bgPick.value = base64data
              resolve()
            }
          }
        } catch (e) {
          reject()
        }
      })
    },
    actorExchange() {
      return new Promise((resolve, reject) => {
        try {
          const imageUrl = this.dragData.src
          const image = new Image()
          // 设置图片的src属性为你想要转换的图片URL
          image.src = imageUrl
          // 当图片加载完成后执行回调函数
          image.crossOrigin = 'anonymous'
          image.onload = () => {
            // 创建一个canvas元素
            const canvas = document.createElement('canvas')
            const ctx = canvas.getContext('2d')
            // 将图片绘制到canvas上
            canvas.width = image.width
            canvas.height = image.height
            ctx.drawImage(image, 0, 0)

            // 将canvas转换为base64格式

            const base64data = canvas.toDataURL('image/png')
            this.dragData.src = base64data
            resolve()
          }
        } catch (e) {
          reject()
        }
      })
    },
    getParam(url) {
      const isVertical =
        +this.actorPick.actor_width < +this.actorPick.actor_height
      return {
        model_uniqueid: this.modelUniqueid,
        video_generate_actor_uid: this.actorPick.uid,
        video_generate_voice_uid: this.voicePick.uid,
        video_generate_layout_background_type: this.bgPick.type,
        video_generate_layout_background_background: this.bgPick.origin,
        video_generate_layout_avatar_x: (this.dragData?.x - this.dragData?.w) * 3,
        video_generate_layout_avatar_y:
          (this.dragData?.y - this.dragData?.h) * 3,
        video_generate_layout_avatar_width: this.dragData?.w * 3,
        video_generate_layout_avatar_height: this.dragData?.h * 3,
        default_cut_bg_image: url
      }
    },
    generateUUID() {
      const timestamp = Date.now().toString(16)
      const random = Math.random().toString(16).slice(2)
      return `${timestamp}${random}`
    },
    setData() {
      getStsApi()
        .then((res) => {
          this.stsData = res.data
          // this.process = this.stsData.host
          // this.process = '/up-api/'
        })
        .catch(() => { })
    },
    finish() {
      return new Promise((resolve, reject) => {
        if (this.bgPick.origin && this.actorPick?.uid && this.voicePick?.uid) {
          Promise.allSettled([this.backgroundExchange(), this.actorExchange()])
            .then(() => {
              const element = this.$refs.canvasRef
              html2Canvas(element, {
                useCORS: true
              })
                .then((canvas) => {
                  // canvas.toDataURL() 可以获取图片的 base64 编码
                  const dataUrl = canvas.toDataURL()
                  const name = '转场图片' + new Date().getTime()
                  // 你可以将 dataUrl 设置为一个 img 标签的 src 属性，或者下载图片等
                  const byteCharacters = atob(dataUrl.split(',')[1])

                  const byteNumbers = new Array(byteCharacters.length)
                  for (let i = 0; i < byteCharacters.length; i++) {
                    byteNumbers[i] = byteCharacters.charCodeAt(i)
                  }
                  const byteArray = new Uint8Array(byteNumbers)
                  const blob = new Blob([byteArray], { type: 'image/png' })

                  // 创建一个新的File对象
                  const file = new File([blob], `${name}.png`, {
                    type: 'image/png'
                  })
                  const signature = this.stsData?.mp?.signature
                  const ossAccessKeyId = this.stsData?.body?.AccessKeyId
                  const policy = this.stsData?.mp?.policy
                  const key =
                    this.stsData?.file_path + this.generateUUID() + '.png'
                  const securityToken = this.stsData.body.SecurityToken
                  const formData = new FormData()

                  formData.append('name', name) // 文件名称
                  formData.append('key', key) // 存储在oss的文件路径
                  formData.append('OSSAccessKeyId', ossAccessKeyId) // //accessKeyId
                  formData.append('policy', policy) // policy
                  formData.append('Signature', signature) // 签名
                  formData.append('x-oss-security-token', securityToken) // 使用STS签名时必传。
                  formData.append('success_action_status', 200)
                  formData.append('file', file, name) // 如果是base64文件，那么直接把base64字符串转成blob对象进行上传即可
                  axios
                    .post(this.stsData.host, formData, {
                      headers: {
                        'Content-Type': 'multipart/form-data',
                        'Auth-Token': getToken()
                      }
                    })
                    .then((rep) => {
                      if (rep.status === 200) {
                        const data = this.getParam(
                          this.stsData.host + '/' + key
                        )
                        generateModel({
                          ...data
                        })
                          .then(() => {
                            resolve(true)
                          })
                          .catch(() => {
                            this.$message.error('模型配置失败')
                          })
                      }
                    })
                    .catch(() => {
                      const data = this.getParam('')
                      generateModel({
                        ...data
                      })
                        .then(() => {
                          resolve(true)
                        })
                        .catch(() => {
                          this.$message.error('模型配置失败')
                        })
                    })
                })
                .catch(() => {
                  const data = this.getParam('')
                  generateModel({
                    ...data
                  })
                    .then(() => {
                      resolve(true)
                    })
                    .catch(() => {
                      this.$message.error('修改模型配置失败')
                    })
                })
            })
            .catch(() => {
              const data = this.getParam('')
              generateModel({
                ...data
              })
                .then(() => {
                  resolve(true)
                })
                .catch(() => {
                  this.$message.error('修改模型配置失败')
                })
            })
        } else {
          reject(false)
        }
      })
    },
    temporarySave() {
      return
    }
  }
}
</script>
<style lang="scss" scoped>
.picked {
  border: 1px solid #04d1b8;
}

.pic-item {
  aspect-ratio: 9 / 16;
}

.pic-item2 {
  aspect-ratio: 16 / 9;
}

.actor-img {
  width: 100%;
  /* 图片宽度100% */
  height: auto;
  /* 高度自适应 */
  max-height: 100%;
  object-fit: cover;
}

.dragg-box {
  position: relative;

  .mb {
    width: calc(50% - 180px);
    height: 100%;
    position: absolute;
    right: 0;
    top: 0;
    z-index: 50;
    background: rgba(255, 255, 255, 0.5);
    pointer-events: none;
  }

  .mb-left {
    left: 0;
  }
}
</style>
